<?php
declare(strict_types=1);

namespace app\common\middleware;

use app\common\exception\AdminException;
use think\facade\Cache;
use think\facade\Log;

class RateLimit
{
    public function handle($request, \Closure $next, $maxRequests = 60, $perSeconds = 60)
    {
        // 客户端标识（支持代理服务器）
        $clientKey = $request->server('HTTP_X_FORWARDED_FOR') ?? $request->ip();

        // 固定时间窗口
        $window = floor(time() / $perSeconds);
        $cacheKey = sprintf('rate_limit:%s:%d', md5($clientKey), $window);

        // Redis原子操作
        try {
            $current = Cache::store('redis')
                ->handler()
                ->incr($cacheKey);

            if ($current === 1) {
                Cache::store('redis')->expire($cacheKey, $perSeconds);
            }
        } catch (\RedisException $e) {
            Log::error('Redis error: ' . $e->getMessage());
            throw new AdminException('服务暂时不可用，请稍后再试', 503);
        }

        if ($current > $maxRequests) {
            throw new AdminException('请求过于频繁', 429, [
                'Retry-After' => $perSeconds - (time() % $perSeconds),
                'X-RateLimit-Limit' => $maxRequests,
                'X-RateLimit-Remaining' => max(0, $maxRequests - $current)
            ]);
        }

        return $next($request);
    }
}